home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Processes / MP Threaded Sort / Sprocket / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1997-03-13  |  10.0 KB  |  385 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.          <5>    11/16/94    DRF        Added explicit #include <SegLoad.h> for latest universal
  15.                                     headers. Also added cast to keep MPW CFront happier.
  16.          <4>    11/16/94    DRF        Add StdFilterProc for THINK C.
  17.          <3>     9/27/94    DRF         AppLib.h is now Sprocket.h
  18.          <2>      9/9/94    DRF        Reordered headers and removed redundant #includes.
  19.  */
  20.  
  21. #include "Sprocket.h"
  22. extern pascal void ExitToShell(void );
  23.  
  24. #include <Fonts.h>
  25. #include <Resources.h>
  26. #include <TextUtils.h>
  27. #include <Threads.h>        //    For YieldToAnyThread()
  28. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  29. #include <SegLoad.h>        //    For ExitToShell()
  30. #include <Controls.h>
  31.  
  32. //    Some types which should probably be defined in <Dialogs.h>
  33. //    NOTE: These must be aligned on 2-byte boundaries
  34. #if defined(powerc) || defined (__powerc)
  35. #pragma options align=mac68k
  36. #endif
  37.  
  38. struct DialogItem
  39.     {
  40.     long    usedByDialogManager;
  41.     Rect    boundsRect;
  42.     char    type;
  43.     char    length;
  44.     };
  45.  
  46. struct DialogItemList            //    a.k.a. a 'DITL'
  47.     {
  48.     short        count;
  49.     DialogItem    firstItem[1];
  50.     };
  51.  
  52. //    Restore default alignment
  53. #if defined(powerc) || defined(__powerc)
  54. #pragma options align=reset
  55. #endif
  56.  
  57. typedef    DialogItem        *DialogItemPtr;
  58. typedef    DialogItemList    **DialogItemListHandle;
  59. typedef    DialogTemplate    **DialogTemplateHandle;
  60.  
  61. #ifndef    powerc
  62. #ifdef    __SC__
  63.  
  64. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  65.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  66.  
  67. pascal Boolean
  68. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  69.     {
  70.     ModalFilterUPP    filterUPP;
  71.  
  72.     //    Dialogs.h
  73.     
  74.     (void) GetStdFilterProc(&filterUPP);
  75.  
  76.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  77.     }
  78.  
  79. #endif
  80. #endif
  81.  
  82. //    private function Prototypes
  83.  
  84. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  85. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  86. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  87. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  88.  
  89.  
  90.  
  91. ///////////////////////////////////////////////////////////
  92. //
  93. //    StandardAlert
  94. //
  95. //    An alternative to Alert() which uses the extended
  96. //    Dialog Manager capabilities.
  97. //
  98. //    I’m not sure we really need this call, but it seems
  99. //    to do the trick just fine.
  100.  
  101. short
  102. StandardAlert(    short dlogID,
  103.                 short defaultItem,                /* = ok */
  104.                 short cancelItem,                /* = 0 */
  105.                 ModalFilterUPP customFilterProc    /* = nil */)
  106.     {
  107.     DialogPtr        theDialog;
  108.     short            itemHit = 0;
  109.     ModalFilterUPP    filterToUse;
  110.     
  111.     HiliteWindowsForModalDialog(false);
  112.  
  113.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  114.     if (defaultItem)
  115.         SetDialogDefaultItem(theDialog,defaultItem);
  116.     if (cancelItem)
  117.         SetDialogCancelItem(theDialog,cancelItem);
  118.  
  119.     if (customFilterProc)
  120.         filterToUse = customFilterProc;
  121.     else
  122.         filterToUse = StandardDialogFilter;
  123.  
  124.     do
  125.         ModalDialog(filterToUse,&itemHit);
  126.     while (itemHit == 0);
  127.     
  128.     DisposeDialog(theDialog);
  129.  
  130.     HiliteWindowsForModalDialog(true);
  131.  
  132.     return itemHit;
  133.     }
  134.  
  135.  
  136. ///////////////////////////////////////////////////////////
  137. //
  138. //    ErrorAlert
  139. //
  140. //    A nice error reporting routine which presents an
  141. //    auto-sized alert box containing the supplied text.
  142. //
  143. //    NOTE:    This routine ASSUMES the following 'DITL'
  144. //            structure:
  145. //
  146. //            item #1 : an “OK” button
  147. //            item #2 : a static text item, somewhere above #1
  148. //
  149. //    NOTE:    We probably need to worry more about low
  150. //            memory conditions-- this can probably
  151. //            be handled by a custom GrowZoneProc and
  152. //            reserve memory area large enough to hold
  153. //            all the space we’d need.
  154. //
  155.  
  156. void
  157. ErrorAlert(short stringList,short whichString)
  158.     {
  159.     Str255                    errorString;
  160.     GrafPtr                    oldPort,windowMgrPort;
  161.     short                    oldFont;
  162.     DialogTemplateHandle    errorDialogTemplate;
  163.     DialogItemListHandle    errorDialogItems;
  164.     TEHandle                aTEHandle;
  165.     Rect                    textRect;
  166.     short                    textHeight;
  167.     short                    additionalSpaceNeeded;
  168.     DialogItemPtr            okButtonItem,errorTextItem;
  169.     const StringPtr            nullStr = (StringPtr) "\p";
  170.  
  171.     GetIndString(errorString,stringList,whichString);
  172.     
  173.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  174.     HLock((Handle) errorDialogTemplate);
  175.     
  176.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  177.     HLock((Handle) errorDialogItems);
  178.     
  179.     //    Find the dialog items
  180.     
  181.     okButtonItem = (**errorDialogItems).firstItem;
  182.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  183.     
  184.     GetPort(&oldPort);
  185.     GetWMgrPort(&windowMgrPort);
  186.     SetPort(windowMgrPort);
  187.     oldFont = qd.thePort->txFont;
  188.     TextFont(systemFont);
  189.  
  190.     aTEHandle = TENew(&textRect,&textRect);
  191.     TESetText(&errorString[1],errorString[0],aTEHandle);
  192.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  193.     TEDispose(aTEHandle);
  194.  
  195.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  196.                             - errorTextItem->boundsRect.top);
  197.  
  198.     if (additionalSpaceNeeded > 0)
  199.         {
  200.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  201.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  202.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  203.         }
  204.         
  205.     TextFont(oldFont);
  206.     SetPort(oldPort);
  207.     
  208.     InitCursor();
  209.     ParamText(errorString,nullStr,nullStr,nullStr);
  210.  
  211.     (void) StandardAlert(kErrorAlertID);
  212.  
  213.     ReleaseResource((Handle) errorDialogTemplate);
  214.     ReleaseResource((Handle) errorDialogItems);
  215.     }
  216.  
  217.  
  218. ///////////////////////////////////////////////////////////
  219. //
  220. //    FatalErrorAlert
  221. //
  222. //    A companion to ErrorAlert which also kills the process.
  223. //
  224.  
  225. void
  226. FatalErrorAlert(short stringList,short whichString)
  227.     {
  228.     ErrorAlert(stringList,whichString);
  229.     ExitToShell();
  230.     }
  231.  
  232.  
  233. ///////////////////////////////////////////////////////////
  234. //
  235. //    StandardDialogFilter and StandardDialogFilterYD
  236. //
  237. //    These function takes care of routing events not meant
  238. //    for the dialog window to other parts of the application.
  239. //
  240. //    Use them as an alternative to passing a NIL ModalFilterProc
  241. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  242. //    filter, these routines properly processes update events
  243. //    to keep background processes running.
  244. //
  245. //    The Thread Manager, if present, is also called to yield
  246. //    control to other cooperative threads within the process.
  247. //
  248. //    Because of pascal calling conventions we need two separate
  249. //    routines, but this is minimized by sharing implementation
  250. //    in FilterProcCommon.
  251. //
  252.  
  253. ModalFilterUPP    StandardDialogFilter
  254. = NewModalFilterProc(StandardDialogFilterProc);
  255.  
  256. ModalFilterYDUPP    StandardDialogFilterYD
  257. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  258.  
  259. ModalFilterUPP    StandardCloseDialogFilter
  260. = NewModalFilterProc(StandardCloseDialogFilterProc);
  261.  
  262.  
  263. pascal Boolean
  264. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  265.     {
  266.     //    Call through common code to check for events we’d like to handle.
  267.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  268.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  269.  
  270.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  271.         return true;
  272.     else
  273.         return (StdFilterProc(theDialog, anEvent, itemHit));
  274.     }
  275.  
  276.  
  277. pascal Boolean
  278. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  279.     {
  280.     //    We don’t call through to StdFilterProc since the
  281.     //    Standard File Package already does everything we need.
  282.  
  283.     return FilterProcCommon(theDialog, anEvent, itemHit);
  284.     }
  285.  
  286. void
  287. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  288.     {
  289.     Handle    itemHandle;
  290.     Rect    itemBox;
  291.     long    finalTicks;
  292.     short    itemType;
  293.     
  294.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  295.  
  296.     HiliteControl((ControlHandle) itemHandle, kControlButtonPart);
  297.     Delay(8,&finalTicks);
  298.     HiliteControl((ControlHandle) itemHandle,0);
  299.     }
  300.  
  301.  
  302. pascal Boolean
  303. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  304.     {
  305.     if ((anEvent->what == keyDown))
  306.         {
  307.         char    c = (char) anEvent->message & charCodeMask;
  308.         
  309.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  310.             {
  311.             *itemHit = kDontSaveDocument;
  312.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  313.             return true;
  314.             }
  315.         }
  316.  
  317.     //    Return through the common code above so that default item processing can happen
  318.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  319.     }
  320.  
  321.  
  322. Boolean
  323. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  324.     {
  325.     switch (anEvent->what)
  326.         {
  327.         case updateEvt:
  328.         case activateEvt:
  329.             //     Update or activate for the dialog window?
  330.             if (theDialog == (DialogPtr) anEvent->message)
  331.                 break;
  332.  
  333.             //    no, fall through to HandleEvent            
  334.             
  335.         case diskEvt:
  336.             HandleEvent(anEvent);
  337.             return(false);
  338.  
  339.         default:
  340.             break;        
  341.         }
  342.  
  343.     if (gHasThreadManager)        //    If we have threads, let them run!
  344.         YieldToAnyThread();
  345.  
  346.     return false;                //    We didn’t handle the event
  347.     }
  348.  
  349.  
  350. //////////////////////////////////////////////////////////////////
  351. //
  352. //    StandardCloseDocument
  353. //
  354. //    Provides the standard human interface for closing a document
  355. //
  356. //    NOTE: When we make TDocument class, this will become a method
  357. //          and probably won’t need any parameters.
  358. //
  359. //    NOTE:    StandardCloseResult matches the dialog items for 
  360.  
  361. StandardCloseResult
  362. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  363.                       Boolean hasNewEditions, Boolean quitting)
  364.     {
  365.     short        whichAlert;
  366.     short        whichString;
  367.     StringPtr    nullStr = (StringPtr) "\p";
  368.     Str255        reasonForClosingStr;
  369.  
  370.     if (hasNewEditions)
  371.         whichAlert = kStandardCloseWithNewPubsAlertID;
  372.     else
  373.         whichAlert = kStandardCloseAlertID;
  374.     
  375.     if (quitting)
  376.         whichString = kQuittingStr;
  377.     else
  378.         whichString = kClosingStr;
  379.  
  380.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  381.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  382.     
  383.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  384.     }
  385.